#pragma once
#include "miniprotobuf_hlp.h"

typedef struct  person
{
	//option  1
	string name;
	//option    2
	string phoneNo;
	//option  3
	int age;
	//repeated  4
	std::vector<string> skill;
}st_person;
class CMiniPb_person
{
public:
	CMiniPb_person(void)
	{
		pFmt = new CEasyFormat();
		memset(&_mask, 0, sizeof(_mask));
	}
public:
	~CMiniPb_person(void)
	{
		if (pFmt != NULL)
		{
			delete pFmt;
		}
	}
public:
	CMiniPb_person(const CMiniPb_person & r )
	{
		pFmt = new CEasyFormat();
		memset(&_mask, 0, sizeof(_mask));
		CMiniPb_person * pr = const_cast<CMiniPb_person *>(&r);
		if (pr->has_name())
		{
			set_name(pr->name());
		}
		if (pr->has_age())
		{
			set_age(pr->age());
		}
		if (pr->has_phoneNo())
		{
			set_phoneNo(pr->phoneNo());
		}
		if (pr->size_of_skill()>0)
		{
			for (unsigned int i=0; i<pr->size_of_skill(); i++)
			{
				add_skill(pr->skill(i));
			}
		}
	}
	CMiniPb_person& operator =(const CMiniPb_person& r)
	{
		//pFmt = new CEasyFormat();
		memset(&_mask, 0, sizeof(_mask));
		CMiniPb_person * pr = const_cast<CMiniPb_person *>(&r);
		if (pr->has_name())
		{
			set_name(pr->name());
		}
		if (pr->has_age())
		{
			set_age(pr->age());
		}
		if (pr->has_phoneNo())
		{
			set_phoneNo(pr->phoneNo());
		}
		if (pr->size_of_skill()>0)
		{
			for (unsigned int i=0; i<pr->size_of_skill(); i++)
			{
				add_skill(pr->skill(i));
			}
		}
		return *this;
	}
public:
	//format
	CFormat* pFmt;
	//idx
	enum {
		e_name = 1,
		e_phoneNo = 2,
		e_age  = 3,
		e_skill = 4,
	};
	//mask
	#define MASK_SIZE 1
	unsigned int _mask[MASK_SIZE];
	SET_BIT_HELP_EASY(_mask,MASK_SIZE);
	HAS_BIT_HELP_EASY(_mask,MASK_SIZE);

	//attr
	OPTION_ATTR(string,name);
	OPTION_ATTR(string,phoneNo);
	OPTION_ATTR(int,age);
	REPEATED_ATTR(string,skill);
public:
	bool parse(const char* pIn, unsigned int packetlen)
	{
		if (pIn == NULL || packetlen == 0)
		{
			return false;
		}
		CBytebuffer bb((char*)pIn, packetlen, pFmt);
		return parse(&bb);
	}
	bool parse(CBytebuffer* pbb)
	{
		if (pbb == NULL)
		{
			return false;
		}
		int tag = 0;
		int datatype = 0;
		while ((tag = pbb->get_tag_datatype(datatype))>0)
		{
			switch(tag)
			{
			case e_name:
				if ( !pbb->parse_string(_name))
				{
					return false;
				}
				set_name(_name);
				break;
			case e_phoneNo:
				if ( !pbb->parse_string(_phoneNo))
				{
					return false;
				}
				set_phoneNo(_phoneNo);
				break;
			case e_age:
				if ( !pbb->parse_varint32(_age))
				{
					return false;
				}
				set_age(_age);
				break;
			case e_skill:
				{
					int size = 0;
					if ( !pbb->parse_varint32(size))
					{
						return false;
					}
					int count = 0;
					if ( !pbb->parse_varint32(count))
					{
						return false;
					}
					for (int i=0; i<count; i++)
					{
						string s;
						if (!pbb->parse_string(s))
						{
							return false;
						}
						add_skill(s);
					}
					break;
				}
			default :
				{
					if (!pbb->parse_unknown_pass((DATA_TYPE)datatype))
					{
						return false;
					}
				}
				break;
			}
		}
		return true;
	}

	int serialize(char* pOut, unsigned int len )
	{
		if (pOut == NULL)
		{
			return -1;
		}
		CBytebuffer bb(pOut, len, pFmt);
		return serialize(&bb);
	}
#define CHECK_RETURN(s)\
	if (!(s))\
	{\
		return -1;\
	}
	int serialize(CBytebuffer* pbb)
	{
		if (pbb == NULL)
		{
			return -1;
		}
		//option
		if (has_name())
		{
			CHECK_RETURN(pbb->write_varint32(pbb->build_tag(e_name, e_dt_with_head_length)));
			CHECK_RETURN(pbb->write_string(_name));
		}
		//option
		if (has_phoneNo())
		{
			CHECK_RETURN(pbb->write_varint32(pbb->build_tag(e_phoneNo, e_dt_with_head_length)));
			CHECK_RETURN(pbb->write_string(_phoneNo));
		}
		//option
		if (has_age())
		{
			CHECK_RETURN(pbb->write_varint32(pbb->build_tag(e_age, e_dt_varint)));
			CHECK_RETURN(pbb->write_varint32(_age));
		}
		//repeated
		if (size_of_skill()>0)
		{
			CHECK_RETURN(pbb->write_varint32(pbb->build_tag(e_skill, e_dt_with_head_length)));
			char temp[1024] = "";
			CBytebuffer bb(temp, 1024, pFmt);
			for (unsigned int i = 0; i<size_of_skill(); i++)
			{
				CHECK_RETURN(bb.write_string(skill(i)));
			}
			CHECK_RETURN(pbb->write_varint32(bb.payload()));
			CHECK_RETURN(pbb->write_varint32(size_of_skill()));
			CHECK_RETURN(pbb->append(temp, bb.payload()));
		}
		return pbb->payload();
	}
};




typedef struct  
{
	int classc;
	st_person who;
	string school;
	std::vector<st_person> mates;
}st_student;

class CMiniPb_student
{
public:
	CMiniPb_student(void)
	{
		pFmt = new CEasyFormat();
		memset(&_mask, 0, sizeof(_mask));
	}
public:
	~CMiniPb_student(void)
	{
		if (pFmt != NULL)
		{
			delete pFmt;
		}
	}
public:
	CMiniPb_student(const CMiniPb_student& r )
	{
		pFmt = new CEasyFormat();
		memset(&_mask, 0, sizeof(_mask));
		CMiniPb_student* pr = const_cast<CMiniPb_student*>(&r);
	}
	CMiniPb_student& operator =(const CMiniPb_student& r)
	{
		//if (r.has_classc())
		//{
		//	set_classc(r.classc());
		//}
		//if (r.has_school())
		//{
		//	set_school(r.school());
		//}
		//if (r.has_who())
		//{
		//	set_who(r.who());
		//}
		return *this;
	}
public:
	//format
	CFormat* pFmt;
	//idx
	enum {
		e_classc = 1,
		e_who = 2,
		e_school  = 3,
		e_mates = 4,
	};
	//mask
#define MASK_SIZE 1
	unsigned int _mask[MASK_SIZE];
	SET_BIT_HELP_EASY(_mask,MASK_SIZE);
	HAS_BIT_HELP_EASY(_mask,MASK_SIZE);

	//attr
	OPTION_ATTR(int,classc);
	OPTION_ATTR(CMiniPb_person,who);
	OPTION_ATTR(string,school);
	REPEATED_ATTR(CMiniPb_person, mates);
public:
	bool parse(const char* pIn, unsigned int packetlen)
	{
		CBytebuffer bb((char*)pIn, packetlen, pFmt);
		return parse(&bb);
	}
	bool parse(CBytebuffer* pbb)
	{
		if (pbb == NULL)
		{
			return false;
		}
		int tag = 0;
		int datatype = 0;
		while ((tag = pbb->get_tag_datatype(datatype))>0)
		{
			switch(tag)
			{
			case e_classc:
				if ( !pbb->parse_varint32(_classc))
				{
					return false;
				}
				_set_bit(e_classc);
				break;
			case e_who:
				{
					int len = 0;
					if ( !pbb->parse_varint32(len))
					{
						return false;
					}
					CBytebuffer tb(pbb->get_cur(), len, pFmt);
					if ( !_who.parse(&tb))
					{
						return false;
					}
					pbb->advance(len);
					_set_bit(e_who);
				}
				break;
			case e_school:
				if ( !pbb->parse_string(_school))
				{
					return false;
				}
				_set_bit(e_school);
				break;
			case e_mates:
				{
					int tlen = 0;
					if ( !pbb->parse_varint32(tlen))
					{
						return false;
					}
					int count = 0;
					if ( !pbb->parse_varint32(count))
					{
						return false;
					}
					for (int i=0; i<count; i++)
					{
						int len = 0;
						if ( !pbb->parse_varint32(len))
						{
							return false;
						}
						CBytebuffer tb(pbb->get_cur(), len, pFmt);
						CMiniPb_person s;
						if ( !s.parse(&tb))
						{
							return false;
						}
						pbb->advance(len);
						add_mates(s);
					}
					break;
				}
			default :
				break;
			}
		}
		return true;
	}

	int serialize(char* pOut, unsigned int len )
	{
		CBytebuffer bb(pOut, len, pFmt);
		return serialize(&bb);
	}
#define CHECK_RETURN(s)\
	if (!s)\
	{\
	return -1;\
	}
	int serialize(CBytebuffer* pbb)
	{
		if (pbb == NULL)
		{
			return -1;
		}
		//option
		if (has_classc())
		{
			CHECK_RETURN(pbb->write_varint32(pbb->build_tag(e_classc, e_dt_varint)));
			CHECK_RETURN(pbb->write_varint32(_classc));
		}
		//option
		if (has_who())
		{
			CHECK_RETURN(pbb->write_varint32(pbb->build_tag(e_who, e_dt_with_head_length)));
			char temp[1024];
			int len = 0;
			CHECK_RETURN((len = _who.serialize(temp, 1024))>0);
			CHECK_RETURN(pbb->write_varint32(len));
			CHECK_RETURN(pbb->append(temp, len));
		}
		//option
		if (has_school())
		{
			CHECK_RETURN(pbb->write_varint32(pbb->build_tag(e_school, e_dt_with_head_length)));
			CHECK_RETURN(pbb->write_string(_school));
		}
		//repeated
		if (size_of_mates() > 0)
		{
			int count = size_of_mates();
			int tlen = 0;
			char tb[1024*10] = "";
			CBytebuffer tempbuf(tb, 1024*10, pFmt);
			for (int i=0; i<count; i++)
			{	
				char temp[1024] = "";
				int len = 0;
				//len = mates(i).serialize(temp,1024);	
				CHECK_RETURN((len = mates(i).serialize(temp, 1024))>0);
				CHECK_RETURN(tempbuf.write_varint32(len));
				CHECK_RETURN(tempbuf.append(temp, len));
			}
			CHECK_RETURN(pbb->write_varint32(pbb->build_tag(e_mates, e_dt_with_head_length)));
			CHECK_RETURN(pbb->write_varint32(tempbuf.payload()));
			CHECK_RETURN(pbb->write_varint32(count));
			CHECK_RETURN(pbb->append(tb, tempbuf.payload()));
		}
		return pbb->payload();
	}
};
